﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Thread = System.Threading.Tasks;
using Microsoft.Practices.Unity;
using Infrastucture;
using TimeSplicerModule.Factories;
using TimeSplicerModule.DomainModels;
using TimeSplicerModule.Security;
using TimeSplicerModule.ViewModels;

namespace TimeSplicerModule.Services
{
    public partial class TaskService : ITaskService
    {
        // TODO: May have to add Schedueld Date

        public TaskViewModel CreateNewViewModel(Guid projectGuid)
        {
            _session = _container.Resolve<ISession>();
            var task = CreateNew(projectGuid);
            var model = ModelConverter.ToModel<TaskViewModel>(task);
            

            model.Schedule = new TaskScheduleModel
            {
                AutoStart = false,
                EndAmPm = Helpers.TimeOfDay.AM,
                IsActive = true,
                EndDate = DateTime.Today,
                EndHour = 10,
                EndMinute = 0,
                IncludeFriday = true,
                IncludeMonday = true,
                IncludeSaturday = false,
                IncludeSunday = false,
                IncludeThursday = true,
                IncludeTuesday = true,
                IncludeWednesday = true,
                StartAmPm = Helpers.TimeOfDay.AM,
                StartDate = DateTime.Today,
                StartHour = 8,
                StartMinute = 0,
                OccuranceType = Helpers.TaskScheduleOccuranceTypes.Weekly
            };

           
            model.OccuranceTypes = new List<string> { Helpers.TaskScheduleOccuranceTypes.Monthly, Helpers.TaskScheduleOccuranceTypes.Weekly, Helpers.TaskScheduleOccuranceTypes.Daily };
            model.TimesOfDay = new List<string> { Helpers.TimeOfDay.AM, Helpers.TimeOfDay.PM };


            // set view model defaults
            model.ActivateButtonVisibility = System.Windows.Visibility.Collapsed;
            model.SuspendButtonVisibility = System.Windows.Visibility.Collapsed;
            model.CompleteButtonVisibility = System.Windows.Visibility.Collapsed;

            return model;
        }

        public TaskViewModel Get(Guid taskGuid)
        {
            _session = _container.Resolve<ISession>();
            var task = _taskFactory.Get(x => x.TaskGuid == taskGuid);

            var model = ModelConverter.ToModel<TaskViewModel>(task);
            model.Status = _session.Statuses.FirstOrDefault(x => x.StatusGuid == model.StatusGuid); //_statusFactory.Get(x => x.StatusGuid == model.StatusGuid);
            model.Project = _projectService.Get(model.ProjectGuid);
            model.Priorities = _session.Priorities; //_priorityFactory.GetList().ToList();
            model.Priority = model.Priorities.FirstOrDefault(x => x.PriorityGuid == model.PriorityGuid);
            model.Categories = _categoryFactory.GetList();
            model.SubCategories = _categoryFactory.GetList().Where(x => x.IsTaskSubCategory).ToList();
            model.FilteredSubCategories = model.SubCategories.Where(x => x.ParentCategoryGuid == model.CategoryGuid).ToList();
            model.CreatedBy = _userFactory.Get(x => x.UserGuid == model.CreatedByGuid);

            // TODO: Need to get the schedule it will be by task guid or dervived task guid
            //model.Schedule = //_scheduleFactory.Get(x => x.TaskGuid == model.TaskGuid
                //|| x.TaskGuid == model.DerivedFromTaskGuid) ?? new TaskScheduleModel();
            model.Schedule = _scheduleService.GetSchedule(model);

            model.OccuranceTypes = new List<string> { Helpers.TaskScheduleOccuranceTypes.Monthly, Helpers.TaskScheduleOccuranceTypes.Weekly, Helpers.TaskScheduleOccuranceTypes.Daily };
            model.TimesOfDay = new List<string> { Helpers.TimeOfDay.AM, Helpers.TimeOfDay.PM };


            var projectRoles = _projectRoleFactory.GetList();
            var users = _userFactory.GetList();
            model.ProjectUsers = _projectUserFactory.GetList(users, projectRoles).Where(x =>
                x.ProjectGuid == model.ProjectGuid
                && x.UserGuid == model.AssignedToGuid).ToList();


            model.Timestamps = _timestampService.GetList(model);
            //model.Hours = GetTaskHours(model.Timestamps);

            // defaults
            model.MakeActiveTaskCheckboxVisibility = System.Windows.Visibility.Collapsed;

            // need to set some disblements

            if (model.Status.Status == Status.In_Progress)
            {
                model.ActivateButtonEnabled = false;
                model.SuspendButtonEnabled = true;
                model.CompletedButtonEnabled = true;
                model.CompletedDateVisibility = System.Windows.Visibility.Collapsed;
            }
            else if (model.Status.Status == Status.Suspended)
            {
                model.ActivateButtonEnabled = true;
                model.SuspendButtonEnabled = false;
                model.CompletedButtonEnabled = true;
                model.CompletedDateVisibility = System.Windows.Visibility.Collapsed;
            }
            else if (model.Status.Status == Status.Completed)
            {
                model.ActivateButtonEnabled = false;
                model.SuspendButtonEnabled = false;


                model.CompletedButtonEnabled = false;
                model.CompletedDateVisibility = System.Windows.Visibility.Visible;
            }
            else if (model.Status.Status == Status.Not_Started)
            {
                model.ActivateButtonEnabled = true;
                model.SuspendButtonEnabled = false;
                model.CompletedButtonEnabled = false;
                model.CompletedDateVisibility = System.Windows.Visibility.Collapsed;
            }

            return model;
        }

        public TaskViewModel Save(TaskViewModel task)
        {
            bool makeActive = task.MakeActiveTask;
            // get a currently in progress task and hold onto it
            var inProgress = GetInProgressTask();

            // the ordering of everytihng in here is kinda whack will need to improve it to make more sense

            _session = _container.Resolve<ISession>();
            if (task.CreatedByGuid == Guid.Empty)
                task.CreatedByGuid = _session.User.UserGuid;

            if (task.AssignedToGuid == _session.User.UserGuid)
            {
                if (makeActive)
                {
                    // make this new taks the in progress taks -  this assums it oly happen on first create
                    task.StartedDate = DateTime.Now;
                    task.Status = _statusFactory.Get(x => x.StatusEnum == Status.In_Progress.ToString());
                    task.StatusGuid = task.Status.StatusGuid;
                    

                    // TODO update project statsus
                    var active = _statusFactory.Get(x => x.StatusEnum == Status.Active.ToString());
                     _projectService.UpdateProjectStatus(task.ProjectGuid, active);


                }
            }


            var t = ModelConverter.ToModel<TaskModel>(task);
            t = _taskFactory.Upsert(t);


            if (task.AssignedToGuid == _session.User.UserGuid)
            {
                if (makeActive)
                {
                    // supspend any in progress user taks
                    //var inProgress = GetInProgressTask();

                    if (inProgress != null)
                    {
                        // suspend that first task
                        Suspend(ModelConverter.ToModel<TaskViewModel>(inProgress));
                    }

                    // create timestamp for new task
                    _timestampService.GenerateNext(t, TimestampType.Activated);

                    // UPDATE START DATE ON POTENTIAL SCHEDULED TASK
                    _scheduleService.StartScheduledTask(task);
                }
            }


            task = _scheduleService.CreateScheduleForTask(task);
           // t.Schedule = task.Schedule;

            // if reccuring then will have to create a schedule
            // TODO: NEED TO HANDLE TURN OFF
            // TODO: NEED TO WORK ON THIS SECTION

            // SOOO How am i going to do this
            // Moving this logic to another class
            //if (t.IsRecurring && !t.IsDerived)
            //{
                

            //    task.Schedule.TaskGuid = t.TaskGuid;
            //    t.Schedule.IsActive = t.IsRecurring;
            //    // going to do something different if derived
            //    t.Schedule = _scheduleFactory.Upsert(t.Schedule);
            //}
            //else if (t.IsRecurring && t.IsDerived)
            //{
            //    t.Schedule.IsActive = t.IsRecurring;
            //    t.Schedule.TaskGuid = t.DerivedFromTaskGuid;
            //    t.Schedule = _scheduleFactory.Upsert(t.Schedule);
            //}

            // NEED TO FIGURE OUT HOW TO TURN OFF REOCURRING
            // think i actually need to split off schedule templates
            // that can be reopened
            // need DerivedFRomTaskGuid so i cn go back and get the tasks

            

            return Get(t.TaskGuid);
        }

        public TaskViewModel Activate(TaskViewModel task)
        {
            _session = _container.Resolve<ISession>();


            // TODO: Need to see if user has another in progress task and suspend it
            var inProgress = _statusFactory.Get(x => x.StatusEnum == Status.In_Progress.ToString());
            var currentTask = _taskFactory.Get(x => x.AssignedToGuid == task.AssignedToGuid
                && x.StatusGuid == inProgress.StatusGuid);

            if (currentTask != null)
            {
                var c = ModelConverter.ToModel<TaskViewModel>(currentTask);
                Suspend(c);
            }

            // hmm looks like it was only out of order
            
            // todo change status
            if (task.StartedDate == DateTime.MinValue)
            {
                task.StartedDate = DateTime.Now;
                
                // UPDATE START DATE ON POTENTIAL SCHEDULED TASK
                _scheduleService.StartScheduledTask(task);
            }

            task.Status = _statusFactory.Get(x => x.StatusEnum == Status.In_Progress.ToString());
            task.StatusGuid = task.Status.StatusGuid;

            var t = Save(task);
            //var t = ModelConverter.ToModel<TaskModel>(task);
            //t = _taskFactory.Save(t);
            



            var active = _statusFactory.Get(x => x.StatusEnum == Status.Active.ToString());
            _projectService.UpdateProjectStatus(t.ProjectGuid, active);


            _timestampService.GenerateNext(t, TimestampType.Activated);

            return Get(t.TaskGuid);
        }

        public TaskViewModel Suspend(TaskViewModel task)
        {
            _session = _container.Resolve<ISession>();

            // need to change status
            task.Status = _statusFactory.Get(x => x.StatusEnum == Status.Suspended.ToString());
            task.StatusGuid = task.Status.StatusGuid;

            var t = Save(task);
            //var t = ModelConverter.ToModel<TaskModel>(task);
            //t = _taskFactory.Save(t);

            _timestampService.Suspend(t);

            return Get(t.TaskGuid);
        }

        public TaskViewModel Complete(TaskViewModel task)
        {
            _session = _container.Resolve<ISession>();

            // todo: change status
            task.CompletedDate = DateTime.Now;
            task.Status = _statusFactory.Get(x => x.StatusEnum == Status.Completed.ToString());
            task.StatusGuid = task.Status.StatusGuid;

            var t = Save(task);
            //var t = ModelConverter.ToModel<TaskModel>(task);
            //t = _taskFactory.Save(t);



            _timestampService.Complete(t);

            // Update POTENTIAL SCHEDULED TASK TO COMPLETED
            _scheduleService.CompleteSheduledTask(task);

            return Get(t.TaskGuid);
        }
    }
}
